import { source, httpConfig } from "../index";
export var Module = {};

export function getModule() {
  return Module;
}
export function fetchRemotePackage(
  packageName,
  packageSize,
  callback,
  errback
) {
  Module.expectedDataFileDownloads++;
  if (
    typeof process === "object" &&
    typeof process.versions === "object" &&
    typeof process.versions.node === "string"
  ) {
    eval(`require("fs").readFile(packageName, function (err, contents) {
      if (err) {
        errback(err);
      } else {
        callback(contents.buffer);
      }
    })`);
    return;
  }
  var xhr = new XMLHttpRequest();
  xhr.open("GET", packageName, true);
  xhr.responseType = "arraybuffer";
  xhr.withCredentials = httpConfig.withCredentials;
  for (const key in httpConfig.headers) {
    xhr.setRequestHeader(key, httpConfig.headers[key]);
  }
  xhr.onprogress = function (event) {
    var url = packageName;
    var size = packageSize;
    if (event.total) size = event.total;
    if (event.loaded) {
      if (!xhr.addedTotal) {
        xhr.addedTotal = true;
        if (!Module.dataFileDownloads) Module.dataFileDownloads = {};
        Module.dataFileDownloads[url] = {
          loaded: event.loaded,
          total: size,
        };
      } else {
        Module.dataFileDownloads[url].loaded = event.loaded;
      }
      var total = 0;
      var loaded = 0;
      var num = 0;
      for (var download in Module.dataFileDownloads) {
        var data = Module.dataFileDownloads[download];
        total += data.total;
        loaded += data.loaded;
        num++;
      }
      total = Math.ceil((total * Module.expectedDataFileDownloads) / num);
      if (Module.setStatus)
        Module.setStatus({
          loaded,
          total,
        });
    } else if (!Module.dataFileDownloads) {
      if (Module.setStatus)
        Module.setStatus({
          loaded,
          total,
        });
    }
  };
  xhr.onerror = function (event) {
    throw new Error("NetworkError for: " + packageName);
  };
  xhr.onload = function (event) {
    if (
      xhr.status == 200 ||
      xhr.status == 304 ||
      xhr.status == 206 ||
      (xhr.status == 0 && xhr.response)
    ) {
      // file URLs can return 0
      var packageData = xhr.response;
      callback(packageData);
    } else {
      throw new Error(xhr.statusText + " : " + xhr.responseURL);
    }
  };
  xhr.send(null);
}
export function initModule() {
  if (!Module.expectedDataFileDownloads) {
    Module.expectedDataFileDownloads = 0;
  }
  (function () {
    // When running as a pthread, FS operations are proxied to the main thread, so we don't need to
    // fetch the .data bundle on the worker
    if (Module.ENVIRONMENT_IS_PTHREAD) return;
    var loadPackage = function (metadata) {
      var PACKAGE_PATH = ""
      if (typeof window === "object") {
        PACKAGE_PATH = window.encodeURIComponent(
          window.location.pathname
            .toString()
            .substring(
              0,
              window.location.pathname.toString().lastIndexOf("/")
            ) + "/"
        );
      } else if (
        typeof process === "undefined" &&
        typeof location !== "undefined"
      ) {
        // web worker
        PACKAGE_PATH = encodeURIComponent(
          location.pathname
            .toString()
            .substring(0, location.pathname.toString().lastIndexOf("/")) + "/"
        );
      }
      var PACKAGE_NAME = source.wechatQRcodeFile;
      var REMOTE_PACKAGE_BASE = source.wechatQRcodeFile;
      if (
        typeof Module.locateFilePackage === "function" &&
        !Module.locateFile
      ) {
        Module.locateFile = Module.locateFilePackage;
        err(
          "warning: you defined Module.locateFilePackage, that has been renamed to Module.locateFile (using your locateFilePackage for now)"
        );
      }
      var REMOTE_PACKAGE_NAME = Module.locateFile
        ? Module.locateFile(REMOTE_PACKAGE_BASE, "")
        : REMOTE_PACKAGE_BASE;
      var REMOTE_PACKAGE_SIZE = metadata["remote_package_size"];


      function handleError(error) {
        console.error("package error:", error);
      }

      var fetchedCallback = null;
      var fetched = Module.getPreloadedPackage
        ? Module.getPreloadedPackage(
            REMOTE_PACKAGE_NAME,
            REMOTE_PACKAGE_SIZE
          )
        : null;

      if (!fetched)
        fetchRemotePackage(
          REMOTE_PACKAGE_NAME,
          REMOTE_PACKAGE_SIZE,
          function (data) {
            if (fetchedCallback) {
              fetchedCallback(data);
              fetchedCallback = null;
            } else {
              fetched = data;
            }
          },
          handleError
        );

      function runWithFS() {
        function assert(check, msg) {
          if (!check) throw msg + new Error().stack;
        }
        // Module["FS_createPath"]("/", "wassm", true, true);

        /** @constructor */
        function DataRequest(start, end, audio) {
          this.start = start;
          this.end = end;
          this.audio = audio;
        }
        DataRequest.prototype = {
          requests: {},
          open: function (mode, name) {
            this.name = name;
            this.requests[name] = this;
            Module.addRunDependency("fp " + this.name);
          },
          send: function () {},
          onload: function () {
            var byteArray = this.byteArray.subarray(this.start, this.end);
            this.finish(byteArray);
          },
          finish: function (byteArray) {
            var that = this;
            // canOwn this data in the filesystem, it is a slide into the heap that will never change
            Module.FS_createDataFile(
              this.name,
              null,
              byteArray,
              true,
              true,
              true
            );
            Module.removeRunDependency("fp " + that.name);
            this.requests[this.name] = null;
          },
        };

        var files = metadata["files"];
        for (var i = 0; i < files.length; ++i) {
          new DataRequest(
            files[i]["start"],
            files[i]["end"],
            files[i]["audio"] || 0
          ).open("GET", files[i]["filename"]);
        }

        function processPackageData(arrayBuffer) {
          assert(arrayBuffer, "Loading data file failed.");
          assert(
            arrayBuffer.constructor.name === ArrayBuffer.name,
            "bad input to processPackageData"
          );
          var byteArray = new Uint8Array(arrayBuffer);
          var curr;
          // Reuse the bytearray from the XHR as the source for file reads.
          DataRequest.prototype.byteArray = byteArray;
          var files = metadata["files"];
          for (var i = 0; i < files.length; ++i) {
            DataRequest.prototype.requests[files[i].filename].onload();
          }
          // Module["removeRunDependency"](
          //   "datafile_/wasm/wechatQRcodeFile.data"
          // );
        }
        // Module["addRunDependency"]("datafile_/wasm/wechatQRcodeFile.data");

        if (!Module.preloadResults) Module.preloadResults = {};

        Module.preloadResults[PACKAGE_NAME] = { fromCache: false };
        if (fetched) {
          processPackageData(fetched);
          fetched = null;
        } else {
          fetchedCallback = processPackageData;
        }
      }
      if (Module.calledRun) {
        runWithFS();
      } else {
        if (!Module.preRun) Module.preRun = [];
        Module.preRun.push(runWithFS); // FS is not initialized yet, wait for it
      }
    };
    loadPackage({
      files: [
        {
          filename: "detect.caffemodel",
          start: 338,
          end: 965768,
        },
        {
          filename: "detect.prototxt",
          start: 965768,
          end: 1008424,
        },
        {
          filename: "sr.caffemodel",
          start: 1008424,
          end: 1032353,
        },
        {
          filename: "sr.prototxt",
          start: 1032353,
          end: 1038337,
        },
      ],
      remote_package_size: 1038337,
    });
  })();
  return Module;
}
